%{
    #include <stdio.h>
    #include "syntaxtree.h"
    extern NODE* child[10];
    int error = 0;
%}

%define api.value.type {struct Node *}
%token  INT
%token  FLOAT
%token  ID
%token  SEMI
%token  COMMA
%token  ASSIGNOP
%token  RELOP
%token  PLUS MINUS STAR DIV
%token  AND OR NOT
%token  DOT
%token  TYPE
%token  LP RP LB RB LC RC
%token  STRUCT
%token  RETURN
%token  IF ELSE
%token  WHILE

%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE


%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left PLUS MINUS
%left STAR DIV
%right NEG NOT
%left LP RP LB RB DOT

%%
//High_level Definitions
Program : ExtDeflist {child[0]= $1;$$ = createNode("Program",@$.first_line,1,NULL); if(error == 0)output($$,0);}
    ;
ExtDeflist : ExtDef ExtDeflist      {child[0]= $1;child[1]= $2;$$ = createNode("ExtDeflist",@$.first_line,2,NULL);}
    | /*empty*/                     {$$ = NULL;}
    ;
ExtDef : Specifier ExtDeclist SEMI  {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("ExtDef",@$.first_line,3,NULL);}
    | Specifier ExtDeclist error    {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \";\".\n",@3.first_line);}
    | Specifier ExtDeclist error RP {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \"(\".\n",@3.first_line);}
    | error SEMI                    {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: specifier error.\n",@1.first_line);}
    | Specifier error SEMI          {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: extdeclist error.\n",@2.first_line);}
    | Specifier SEMI                {child[0]= $1;child[1]= $2;$$ = createNode("ExtDef",@$.first_line,2,NULL);}
    | Specifier FunDec CompSt       {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("ExtDef",@$.first_line,3,NULL);}
    | Specifier FunDec error RC     {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \"{\".\n",@3.first_line);}
    | error FunDec CompSt           {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: specifier error.\n",@1.first_line);}
    ;
ExtDeclist : VarDec           {child[0]= $1;$$ = createNode("ExtDeclist",@$.first_line,1,NULL);}
    | VarDec COMMA ExtDeclist {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("ExtDeclist",@$.first_line,3,NULL);}
    ;
//Specifiers
Specifier : TYPE      {child[0]= $1;$$ = createNode("Specifier",@$.first_line,1,NULL);}
    | StructSpecifier {child[0]= $1;$$ = createNode("Specifier",@$.first_line,1,NULL);}
    ;
StructSpecifier : STRUCT OptTag LC DefList RC {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;child[4]= $5;$$ = createNode("StructSpecifier",@$.first_line,5,NULL);}
    | STRUCT OptTag LC DefList error          {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \"}\".\n",@5.first_line);}
    | STRUCT Tag                              {child[0]= $1;child[1]= $2;$$ = createNode("StructSpecifier",@$.first_line,2,NULL);}
    ;
OptTag : ID {child[0]= $1;$$ = createNode("OptTag",@$.first_line,1,NULL);}
    |       {$$ = NULL;}
    ;
Tag : ID {child[0]= $1;$$ = createNode("Tag",@$.first_line,1,NULL);}
    ;
//Declarators
VarDec : ID            {child[0]= $1;$$ = createNode("VarDev",@$.first_line,1,NULL);}
    | VarDec LB INT RB {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;$$ = createNode("VarDec",@$.first_line,4,NULL);}
    | VarDec LB error  {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \"]\".\n",@3.first_line);}
    | error RB         {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \"[\".\n",@1.first_line);}
    ;
FunDec : ID LP VarList RP {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;$$ = createNode("FunDec",@$.first_line,4,NULL);}
    | ID LP RP            {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("FunDec",@$.first_line,3,NULL);}
    | ID LP error         {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \")\".\n",@3.first_line);}
    ;// 缺少左括号被识别为VarDec，在ExtDef中处理
VarList : ParamDec COMMA VarList {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("VarList",@$.first_line,3,NULL);}
    | ParamDec                   {child[0]= $1;$$ = createNode("VarList",@$.first_line,1,NULL);}
    ;
ParamDec : Specifier VarDec {child[0]= $1;child[1]= $2;$$ = createNode("ParamDec",@$.first_line,2,NULL);}
    ;
//Statements
CompSt : LC DefList StmtList RC    {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;$$ = createNode("CompSt",@$.first_line,4,NULL);}
    | LC DefList StmtList error RC {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Def or Stmt error.\n",@4.first_line);}
    ;
StmtList : Stmt StmtList {child[0]= $1;child[1]= $2;$$ = createNode("StmtList",@$.first_line,2,NULL);}
    | /*empty*/          {$$ = NULL;}
    ;
Stmt :  Exp SEMI                              {child[0]= $1;child[1]= $2;$$ = createNode("Stmt",@$.first_line,2,NULL);}
    | Exp error                               {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \";\".\n",@2.first_line);}
    | CompSt                                  {child[0]= $1;$$ = createNode("Stmt",@$.first_line,1,NULL);}
    | RETURN Exp SEMI                         {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Stmt",@$.first_line,3,NULL);}
    | IF LP Exp RP Stmt %prec LOWER_THAN_ELSE {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;child[4]= $5;$$ = createNode("Stmt",@$.first_line,5,NULL);}
    | IF LP Exp RP Stmt ELSE Stmt             {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;child[4]= $5;child[5]= $6;child[6]= $7;$$ = createNode("Stmt",@$.first_line,5,NULL);}
    | WHILE LP Exp RP Stmt                    {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;child[4]= $5;$$ = createNode("Stmt",@$.first_line,5,NULL);}
    | IF error SEMI                           {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \"(\".\n",@3.first_line);}
    | Exp LB error SEMI                       {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \"]\".\n",@3.first_line);}
    | LP error SEMI                           {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \")\".\n",@3.first_line);}
    | ID LP error SEMI                        {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \")\".\n",@3.first_line);}
    | Exp error SEMI                          {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: syntax error. \n",@2.first_line);} 
    | RETURN Exp error                        {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \";\".\n",@3.first_line);}
    ;
//Local Definitions
DefList : Def DefList {child[0]= $1;child[1]= $2;$$ = createNode("DefList",@$.first_line,2,NULL);}
    | /*empty*/       {$$ = NULL;}
    ;
Def : Specifier DecList SEMI {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Def",@$.first_line,3,NULL);}
    | Specifier error SEMI   {error = 1;createNode("Error",@$.first_line,0,NULL);printf("Error type B at Line %d: Missing \";\".\n",@2.first_line);}
    ;
DecList : Dec           {child[0]= $1;$$ = createNode("DecList",@$.first_line,1,NULL);}
    | Dec COMMA DecList {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("DecList",@$.first_line,3,NULL);}
    ;
Dec : VarDec              {child[0]= $1;$$ = createNode("Dec",@$.first_line,1,NULL);}
    | VarDec ASSIGNOP Exp {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Dec",@$.first_line,3,NULL);}
    ;
//Expressions
Exp : Exp ASSIGNOP Exp    {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp AND Exp         {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp OR Exp          {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp RELOP Exp       {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp PLUS Exp        {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp MINUS Exp       {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp STAR Exp        {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp DIV Exp         {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | LP Exp RP           {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | MINUS Exp %prec NEG {child[0]= $1;child[1]= $2;$$ = createNode("Exp",@$.first_line,2,NULL);}
    | NOT Exp             {child[0]= $1;child[1]= $2;$$ = createNode("Exp",@$.first_line,2,NULL);}
    | ID LP Args RP       {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;$$ = createNode("Exp",@$.first_line,4,NULL);}
    | ID LP RP            {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | Exp LB Exp RB       {child[0]= $1;child[1]= $2;child[2]= $3;child[3]= $4;$$ = createNode("Exp",@$.first_line,4,NULL);}
    | Exp DOT ID          {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Exp",@$.first_line,3,NULL);}
    | ID                  {child[0]= $1;$$ = createNode("Exp",@$.first_line,1,NULL);}
    | INT                 {child[0]= $1;$$ = createNode("Exp",@$.first_line,1,NULL);}
    | FLOAT               {child[0]= $1;$$ = createNode("Exp",@$.first_line,1,NULL);}
    ;
//arguments
Args : Exp COMMA Args {child[0]= $1;child[1]= $2;child[2]= $3;$$ = createNode("Args",@$.first_line,3,NULL);}
    | Exp             {child[0]= $1;$$ = createNode("Args",@$.first_line,1,NULL);}
    ;  

%%

yyerror(char* msg){
    /* extern int yylineno;
    extern char* yytext;
    printf("Error type B at Line %d: %s\n",yylineno,msg); */
}
